package main

import (
	"fmt"
	"io"
	"os"
	"rc/config"
	"rc/logger"
	"rc/subcommands"
	"rc/utils"
	"strings"

	"rc/repo"

	"github.com/chzyer/readline"
	"github.com/urfave/cli"
)

var completer = readline.NewPrefixCompleter(
	readline.PcItem("list"),
	readline.PcItem("login"),
	readline.PcItem("exec"),
	readline.PcItem("set"),
	readline.PcItem("get"),
	readline.PcItem("put"),
	// readline.PcItem("put",
	// 	readline.PcItemDynamic(listFiles("./"),
	// 		readline.PcItem("with",
	// 			readline.PcItem("following"),
	// 			readline.PcItem("items"),
	// 		),
	// 	),
	// ),
	readline.PcItem("set"),
	readline.PcItem("help"),
	readline.PcItem("exit"),
	readline.PcItem("q"),
)

var (
	version = "v2017.11.29"
	build   = "develop build, not release"
)

func init() {
	cfg := config.GetConfig()
	// change by set subcommand or rc options
	var err = logger.InitLogger(cfg.Logger.Level, cfg.Logger.Typ, cfg.Logger.LogPath)
	displayError("init logger", err)
	// change by set subcommand or rc options
	err = repo.InitRepo(cfg.RepoPath)
	displayError("init repo", err)
}

func usage(w io.Writer, invalidInfo string) {

	if invalidInfo != "" {
		io.WriteString(w, utils.FgRed("invalid command: "+invalidInfo+"\n"))
	}
	io.WriteString(w, "commands:\n")
	io.WriteString(w, completer.Tree("    "))
}

func filterInput(r rune) (rune, bool) {
	switch r {
	// block CtrlZ feature
	case readline.CharCtrlZ:
		return r, false
	}
	return r, true
}

func main() {
	app := cli.NewApp()
	app.Name = "rc"
	app.EnableBashCompletion = true
	app.Version = fmt.Sprintf("%s\nbuild: %s", version, build)
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "i",
			Usage: "is interactive",
		},
	}
	app.Action = func(c *cli.Context) error {
		if c.Bool("i") {
			return interactiveMode(c)
		} else {
			fmt.Println("no interactive")
			return nil
		}
	}
	app.Commands = subcommands.GenCliCommands()

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
		displayError("main", err)
		os.Exit(1)
	}
}

func interactiveMode(c *cli.Context) error {
	rl, err := readline.NewEx(&readline.Config{
		Prompt:          "\033[31m»\033[0m ",
		HistoryFile:     "/tmp/history.tmp",
		AutoComplete:    completer,
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",

		// HistorySearchFold:   true,
		// FuncFilterInputRune: filterInput,
	})
	if err != nil {
		return err
	}
	defer rl.Close()

	for {
		line, err := rl.Readline()
		displayError("read command line", err)
		line = strings.TrimSpace(line)

		switch {
		case strings.HasPrefix(line, "list"):
			args := utils.ParseArgs(line)
			displayError("list command", subcommands.List(args))
		case strings.HasPrefix(line, "login"):
			args := utils.ParseArgs(line)
			displayError("login command", subcommands.Login(args))
		case strings.HasPrefix(line, "exec"):
			args := utils.ParseArgs(line)
			displayError("exec command", subcommands.Exec(args))
		case strings.HasPrefix(line, "get"):
			args := utils.ParseArgs(line)
			displayError("get command", subcommands.Get(args))
		case strings.HasPrefix(line, "put"):
			args := utils.ParseArgs(line)
			displayError("put command", subcommands.Put(args))
		case strings.HasPrefix(line, "set"):
			args := utils.ParseArgs(line)
			displayError("set command", subcommands.Set(args))
		case line == "exit":
			goto exit
		case line == "q":
			goto exit
		case line == "help":
			usage(rl.Stdout(), "")
		default:
			usage(rl.Stderr(), line)
		}
	}
exit:
	return nil
}

func displayError(errPosition string, err error) {
	if err != nil {
		fmt.Printf("ERROR at %s: %s\n", errPosition, err)
	}
}
